<?php

namespace app\service;

use app\exception\ParameterException;
use app\model\Task;
use app\model\TaskOrder;
use app\utils\Task as TaskEmun;
use app\utils\TaskOrderEmun;
use app\utils\UserMoneyEmun;
use think\facade\Db;
use app\model\Member;
use app\model\UserMoney;
class TaskOrderService
{

    private $taskOrder;
    private $member;

    private $userMoney;

    public function __construct(){
        $this->taskOrder = new TaskOrder;
        $this->member = new Member;
        $this->userMoney = new UserMoney;
    }

    public function list($params = []){

        $page = $params['page'] ?? 1;
        $pageSize = $params['pageSize'] ?? 10;
        $where = [];
        if(!empty($params['username'])) $where[] = ['member.username', 'like', '%'.trim($params['username']).'%'];
        if(!empty($params['status']) && $params['status']!='') $where[] = ['task_order.status', '=', $params['status']];
        if(!empty($params['order_sn'])) $where[] = ['task_order.order_sn', 'like', '%'.trim($params['order_sn']).'%'];
        $result = $this->taskOrder->join('member', 'task_order.member_id = member.id', 'LEFT')
            ->field('task_order.*, member.nickname, member.username,member.phone')
            ->order(['task_order.id'=>'DESC'])
            ->where($where)->paginate([
            'list_rows'=> $pageSize,
            'page' => $page
        ])->append(['status_text']);

        return $result;

    }

    public function apiList($params = [])
    {

        $member_id  = request()->_mid;

        $page = $params['page'] ?? 1;
        $pageSize = $params['pageSize'] ?? 10;
        $where []= ['member_id','=',$member_id];
        if (!empty($params['title'])) $where[] = ['task_order.task_name', 'like', '%' . trim($params['title']) . '%'];
        if (isset($params['status']) && $params['status'] != '-3') $where[] = ['task_order.status', '=', $params['status']];

        if (!empty($params['task_data'])) $where[] = ['task_order.task_data', 'like', '%' . trim($params['task_data']) . '%'];

        if (!empty($params['startTime'])) $where[] = ['task_order.created_at', '>=', trim($params['startTime']) ];

        if (!empty($params['endTime'])) $where[] = ['task_order.created_at', '<=',  trim($params['endTime'])];

        $result = $this->taskOrder->join('member', 'task_order.member_id = member.id', 'LEFT')
            ->join('task', 'task.id = task_order.task_id', 'LEFT')
            ->field('task_order.*, member.nickname, member.username,member.phone,task.cover')
            ->order(['task_order.id' => 'DESC'])
            ->where($where)->paginate([
                'list_rows' => $pageSize,
                'page' => $page
            ])->append(['status_text']);

        return $result;
    }

    public function update($id, $param)
    {
        $taskOrder = $this->taskOrder->find($id);
        $admin_id  = request()->_uid;
        if(!$taskOrder) throw new ParameterException("任务订单不存在");

        if ($param['status']==TaskOrderEmun::TASK_ORDER_STATUS_REFUSE && empty($param['notes'])) throw new ParameterException("请填写拒绝理由");

        $param['audit_time']=date('Y-m-d H:i:s');

        //审核成功
        if($taskOrder['status'] == TaskOrderEmun::TASK_ORDER_STATUS_PASS) throw new ParameterException("审核成功的无法修改!");

        if($param['status'] == TaskOrderEmun::TASK_ORDER_STATUS_PASS){

            $price = $taskOrder['price'];

            // 加载指定ID的用户信息，并对其进行排他性锁定以防止并发修改
            $member = $this->member->lock(true)->where('id', $taskOrder->member_id)->find();
            if(empty($member)) throw new ParameterException("用户不存在");

            // 开始数据库事务
            Db::startTrans();
            try {

                //上级抽成
                if($member->pid > 0){
                    $percentage = $this->getPercentageByMemberId($member->pid,$taskOrder['task_id']);

                    if($percentage){

                        $levelMember = $this->member->lock(true)->where('id', $member->pid)->find();;

                        $percentagePrice = sprintf("%.2f", $price*$percentage/100);

                        $price = sprintf("%.2f", $price-$percentagePrice);
                        $levelMember->money = sprintf("%.2f", $levelMember->money+$percentagePrice);
                        $levelMember->total_money = sprintf("%.2f", $levelMember->total_money+$percentagePrice);
                        $this->userMoney->create([
                            'member_id' => $levelMember->id,
                            'price' => $percentagePrice,
                            'type' => UserMoneyEmun::USER_MONEY_TYPE_DRAW,
                            'remark' => '任务抽成发放',
                            'admin_id' => $admin_id,
                            'balance' => $levelMember->money,
                            'target_id'=>$taskOrder->id
                        ]);
                        $levelMember->save();
                    }
                }

                // 更新用户余额
                $member->money = sprintf("%.2f", $member->money+$price);
                if($price>0) $member->total_money = sprintf("%.2f", $member->total_money+$price);
                $member->save();
                // 创建钱包记录，记录用户的余额变动详情
                $this->userMoney->create([
                    'member_id' => $member->id,
                    'price' => $price,
                    'type' => $param['type']??UserMoneyEmun::USER_MONEY_TYPE_ORDER,
                    'remark' => $param['remark']??'任务奖励发放',
                    'admin_id' => $admin_id,
                    'balance' => $member->money,
                    'target_id'=>$taskOrder->id
                ]);
                 //数据库存在的字段才更新
                $taskOrder->allowField(['status','audit_time','notes'])->save($param);
                // 提交事务
                Db::commit();
                return true;
            }catch (\Exception $e){
                // 回滚事务以撤销所有更改
                Db::rollback();
                // 抛出异常以报告错误
                throw new ParameterException($e->getMessage());
            }
        }

       

    }

    public function delete($id)
    {
        return $this->taskOrder->destroy($id);
    }

    public function save($params)
    {
        //生成订单号
        $params['order_sn'] = generateSnowflakeId();
        $task = (new Task())->find($params['id']);
        if($task['status'] == TaskEmun::TASK_STATUS_DISABLE) throw new ParameterException("任务已关闭");
        if($task['is_attachment']==1 && empty($params['imgs'])) throw new ParameterException("请上传图片");
        $params['vip_price'] = sprintf("%.2f",$task['price']-$task->getData('price'));
        $params['price'] = $task['price'];
        $params['task_id'] = $params['id'];
        $params['member_id'] = request()->_mid;
        $params['task_name']= $task['title'];
        if(isset($params['id'])) unset($params['id']);
        if(!empty($params['imgs'])) $params['imgs'] = json_encode($params['imgs']);

        if(empty($params['imgs'])) unset($params['imgs']);

        return $this->taskOrder->allowField(['member_id','task_id','order_sn','price','vip_price','task_data','task_name'])->create($params);
    }

    /**
     * 批量更新任务单状态
     *
     * @param array $params 包含需要更新的任务单ID数组、新状态和可选的备注
     * @throws ParameterException 如果参数不满足特定条件则抛出异常
     * @return string 更新结果的字符串描述
     */
    public function batchUpdateStatus($params)
    {
        // 提取参数中的任务单ID数组和新状态，若未提供则设为空数组和0（默认状态）
        $ids = $params['ids']??[];
        $status = $params['status']??0;

        // 提取参数中的备注，若未提供则设为空字符串
        $notes = $params['notes']??'';

        // 如果新状态为拒绝且未提供备注，则抛出异常要求填写拒绝理由
        if($status==TaskOrderEmun::TASK_ORDER_STATUS_REFUSE && empty($notes)) throw new ParameterException("请填写拒绝理由");

        // 如果未提供任务单ID数组，则抛出异常要求选择任务单
        if(empty($ids)) throw new ParameterException("请选择任务单!");

        // 查询给定ID数组的任务单，若查询结果为空，则抛出异常表明任务单不存在
        $taskOrder = $this->taskOrder->whereIn('id',$ids)->select();

        if(empty($taskOrder)) throw new ParameterException("任务单不存在!");

        // 审核通过的情况
        if($status==TaskOrderEmun::TASK_ORDER_STATUS_PASS){
            // 初始化成功和失败计数器
            $success=0;
            $error=0;

            // 遍历每个任务单，尝试将其状态更新为审核通过
            foreach ($taskOrder as $value){
                $result = $this->statusPass($value);

                // 根据更新结果，相应增加成功或失败计数器
                if($result) $success++;
                else $error++;
            }

            // 返回审核通过的成功和失败数量
            return "审核通过成功:".$success."条,失败:".$error."条!";
        }

        // 如果新状态不是审核通过，则批量更新任务单状态和备注，排除已审核通过的任务单
        $saveCnt = $this->taskOrder->whereIn('id',$ids)->where('status','!=',TaskOrderEmun::TASK_ORDER_STATUS_PASS)->save(['status'=>$status,'notes'=>$notes]);

        // 返回更新状态成功的任务单数量
        return "操作成功:".$saveCnt."条!";
    }

    /**
     * 审核通过任务订单
     *
     * 当任务订单审核通过时，此方法用于更新任务订单状态，并相应地更新用户的余额
     * 如果任务订单已经被审核通过，则不执行任何操作并返回false
     *
     * @param array $taskOrderModel 任务订单数据数组，包含价格和状态等信息
     * @return bool 返回true表示成功更新，返回false表示操作失败或任务订单已审核通过
     */
    public function statusPass($taskOrderModel)
    {
        // 获取任务订单的价格
        $price = $taskOrderModel['price'];

        // 只有待审核的才能审核通过
        if($taskOrderModel['status']!=TaskOrderEmun::TASK_ORDER_STATUS_WAIT) return false;

        // 获取当前管理员ID
        $admin_id  = request()->_uid;
        // 加载指定ID的用户信息，并对其进行排他性锁定以防止并发修改
        $member = $this->member->lock(true)->where('id', $taskOrderModel->member_id)->find();
        // 如果用户不存在，则返回false
        if(empty($member)) return false;

        // 开始数据库事务
        Db::startTrans();
        try {
            //上级抽成
            if($member->pid > 0){
                $percentage = $this->getPercentageByMemberId($member->pid,$taskOrderModel['task_id']);

                if($percentage){

                    $levelMember = $this->member->lock(true)->where('id', $member->pid)->find();;

                    $percentagePrice = sprintf("%.2f", $price*$percentage/100);

                    $price = sprintf("%.2f", $price-$percentagePrice);
                    $levelMember->money = sprintf("%.2f", $levelMember->money+$percentagePrice);
                    $levelMember->total_money = sprintf("%.2f", $levelMember->total_money+$percentagePrice);
                    $this->userMoney->create([
                        'member_id' => $levelMember->id,
                        'price' => $percentagePrice,
                        'type' => UserMoneyEmun::USER_MONEY_TYPE_DRAW,
                        'remark' => '任务抽成发放',
                        'admin_id' => $admin_id,
                        'balance' => $levelMember->money,
                        'target_id'=>$taskOrderModel->id
                    ]);
                    $levelMember->save();
                }
            }

            // 更新用户余额，保留两位小数
            $member->money = sprintf("%.2f", $member->money+$price);
            // 如果价格大于0，则更新用户的总入账金额
            $member->total_money = sprintf("%.2f", $member->total_money+$price);
            // 保存用户信息
            $member->save();

            // 创建钱包记录，记录用户的余额变动详情
            $this->userMoney->create([
                'member_id' => $member->id,
                'price' => $price,
                'type' => $param['type']??UserMoneyEmun::USER_MONEY_TYPE_ORDER,
                'remark' => $param['remark']??'任务奖励发放',
                'admin_id' => $admin_id,
                'balance' => $member->money,
                'target_id'=>$taskOrderModel->id
            ]);

            // 更新任务订单状态为审核通过
            $taskOrderModel->status = TaskOrderEmun::TASK_ORDER_STATUS_PASS;
            // 保存任务订单信息
            $taskOrderModel->save();

            // 提交事务
            Db::commit();
            // 返回成功标志
            return true;
        }catch (\Exception $e){
            // 回滚事务
            Db::rollback();
            // 返回失败标志
            return false;
        }
    }

    public function countsByPid($pid)
    {
        $result = $this->taskOrder->join("member","member.id=task_order.member_id","LEFT")->where('pid',$pid)->sum("price");

        return $result;
    }

    public function countsByMemberId($memberId)
    {
        $result = $this->taskOrder->where('member_id',$memberId)->sum("price");

        return $result;
    }

    public function getPercentageByMemberId($memberId,$taskId)
    {
        $res = (new PercentageService())->getProportion($memberId,$taskId);
        if($res) return $res;
        return $this->member->where('id',$memberId)->value('percentage');
    }
}
